#include <iostream>
using std::cout;
using std::endl;


//在同一个源文件中尽量避免
//多个通用模板之间形成重载
//因为很难根据调用情况分析到底使用了哪个模板
//
//尽量使用隐式实例化
//
/* template <class T> */
/* T add(T t1,T t2) */
/* { */ 
/*     cout << "模板一" << endl; */
/*     return t1 + t2; */ 
/* } */


//重要！
//T1/T2/...  多个类型参数可以实例化为相同的类型
template <class T1,class T2>
T1 add(T1 t1,T2 t2){
    cout << "模板二" << endl;
    return t1 + t2;
}

void test0(){
    short s1 = 1, s2 = 2;
    int i1 = 3, i2 = 4;
    long l1 = 5, l2 = 6;
    double d1 = 1.9, d2 = 2.2;
    
    //在具体的调用时
    //根据传入的参数推导出T的类型应该实例化为short
    //所有由函数模板实例化出一个能够计算short型数据相加的
    //模板函数
    //推导的方式称之为隐式实例化
    cout << "add(s1,s2): " << add(s1,s2) << endl;
    cout << "add(i1,i2): " << add(i1,i2) << endl;
    cout << "add(l1,l2): " << add(l1,l2) << endl;

    //指定了T此时应该实例化为int
    //此时指定了类型参数，就不会再根据传入的参数的实际类型
    //进行推导
    //指定的方式称之为显式实例化
    cout << "add(d1,d2): " << add<int>(d1,d2) << endl;  
}

void test1(){
    int num = 2;
    double num2 = 3.7;
    cout << add(num2,num) << endl;
    cout << add(num,num2) << endl;

    cout << endl;
    cout << add<int,double>(num,num2) << endl;

    cout << endl;
    cout << add<double>(num,num2) << endl;

    //匹配模板二，不需要让参数进行任何的类型转换
    //如果匹配模板一，需要让第二个参数进行类型转换
    //所以编译器会选择更匹配的模板
    //(尽量少地让参数进行类型转换)
    cout << add<int>(num,num2) << endl;
}

int main(void){
    test1();
    return 0;
}
